Chapter 4: Functions, Numpy and Biopython
Chapter 4: Functions, Numpy and Biopython
4.1 Functions
Imagine this…
You want to calculate the GC content of a sequence.
seq = "ATGCGTAGGCTA"
gc = 0
for n in seq:
if n == "G" or n == "C":
gc += 1
print(gc / len(seq))Now imagine you have 100 sequences…
👉 Would you copy this code 100 times?
❌ Not scalable
❌ Hard to maintain
❌ Error-prone
The solution are Functions. A function is a way to group code that performs a specific task.
👉 Instead of repeating code, we reuse it
🧠 Think of a function as a machine
Input → [ function ] → Output
Using our example
“ATGCGT” → [ GC function ] → 0.5
4.1.1 What is a function?
Python Functions are a block of statements that does a specific task. The idea is to put some commonly or repeatedly done task together and make a function so that instead of writing the same code again and again for different inputs, we can do the function calls to reuse code contained in it over and over again.

Question: Have you already used functions? Which ones?
Question: What would happen if we didn’t have functions?
Answer here
4.1.2 Function definition
We can define a function, using def keyword. A function might take input in the form of parameters. The syntax to declare a function is:

—- Let’s do an example! —-
Here, we define a function using def that prints a welcome to UBDS message when called.
def fun():
print("Welcome to UBDS")What is happening here?
def→ tells Python we are defining a function
function_name→ name of the function
parameters→ inputs (optional)
:→ starts the function block
- Indentation → defines the code inside the function
But it is not printing Welcome to UBDS, why? Because a function only runs when we call it**
4.1.3 Function calling
After creating a function, call it by using the name of the functions followed by parenthesis containing parameters of that particular function.
—- Let’s do an example! —-
Here, we call the function we’ve done before.
fun()What happens if we define the function but never call it?
Can we call the function multiple times?
Answer here
4.1.4 Function arguments
Arguments are the values passed inside the parenthesis of the function. A function can have any number of arguments separated by a comma. They allow us to give input to the function.
—- Let’s do an example! —-
Now we define a function that takes name as argument:
def welcome(name):
print("Welcome", name)
welcome("Anna")What is happening here?
nameis a parameter (inside the function definition)
- “Anna”, “John” are arguments (values we pass)
👉 The function behaves differently depending on the input
Very important!!! - Parameter → variable inside the function
- Argument → actual value passed to the function
Python supports various types of arguments that can be passed at the time of the function call. Below are types of function argument types:
4.1.4.1 Default Arguments
A default argument is a parameter that has a default value. If we do not provide a value when calling the function, the default value is used.
Default arguments are optional inputs
👉 If you don’t provide them → Python fills them automatically
—- Let’s do an example! —-
We are printing the values of the x and y axis
def myFun(x, y=50):
print("x: ", x)
print("y: ", y)
myFun(10)What is happening here?
- We pass only one argument →
x = 10
yis not provided → Python uses the default value (50)
Question: What will happen if we actually give a value to y too?
# Write your answer here4.1.4.2 Keyword Arguments
Values are passed by explicitly specifying the parameter names, so the order doesn’t matter.
👉 This means the order does not matter
—- Let’s do an example! —-
We are printing the name of a student and the subject he is enrolled to:
def school(student, subject):
print(student, subject)
school(student='Anna', subject='Bioinformatics')
school(subject='Bioinformatics', student='Anna')What is happening here?
- We specify the parameter names
- Python knows exactly where each value goes
- Order does not matter
4.1.4.3 Positional Arguments
Values are assigned to parameters based on their order in the function call.
—- Let’s do an example! —-
We are printing the name of a student and his age:
def nameAge(name, age):
print("Hi, I am", name)
print("My age is ", age)
print("Case-1:")
nameAge("Olivia", 27)
print("\nCase-2:")
nameAge(27, "Olivia")What is happening here?
Case 1:
name = “Olivia”
age = 27
✔️ Correct output
Case 2:
name = 27
age = “Olivia”
❌ Wrong assignment!
–> Python assigns values by position, not by meaning
Positional arguments = values are matched based on order
- First value → first parameter
- Second value → second parameter
Question: Can we mix positional and keyword arguments?
# Try the code before mixing both argument types4.1.4.4 Arbitrary Arguments
Allow a function to accept a variable number of inputs. This is done using two special symbols: * args: collects extra positional (non-keyword) arguments as a tuple. *kwargs: collects extra keyword arguments as a dictionary.
—- Let’s do an example! —-
This code separately shows non-keyword (*args) and keyword (**kwargs) arguments in the same function.
def myFun(*args, **kwargs):
print("Non-Keyword Arguments (*args):")
for arg in args:
print(arg)
print("\nKeyword Arguments (**kwargs):")
for key, value in kwargs.items():
print(f"{key} == {value}")
myFun('Hey', 'Welcome', first='Geeks', mid='for', last='Geeks')What is happening here?
- “Hey”, “Welcome” → go into
args
- first=“Geeks”, … → go into
kwargs
👉 Python separates positional and keyword arguments automatically
Questions:
- What happens if we pass only positional arguments?
- What happens if we pass only keyword arguments?
# Write your answer here4.1.5 Return Statement
The return statement ends a function and sends a value back to the caller. It can return any data type, multiple values (packed into a tuple), or None if no value is given. It allows the function to produce a result
Syntax:
return [expression]Parameters: return ends the function, [expression] is the optional value to return (defaults to None).
—- Let’s do an example! —-
This function returns the square value of the entered number
def sq_value(num):
"""This function returns the square
value of the entered number"""
return num**2
print(sq_value(2))
print(sq_value(-4))What is happening here?
- The function computes
num**2
returnsends the result back
print()displays it
def sq_value(num):
print(num**2)
result = sq_value(2)
print(result)What happens here?
- The function prints the value
- But returns nothing
👉 result = None ❗
print()→ shows something on screen
return→ gives a value back
4.2 Python Numpy
Numpy is a general-purpose array-processing package. It provides a high-performance multidimensional array object and tools for working with these arrays. It is the fundamental package for scientific computing with Python. Besides its obvious scientific uses, Numpy can also be used as an efficient multi-dimensional container of generic data.

4.2.1 Arrays in Numpy
A NumPy array is a structured collection of elements of the same data type stored in a table format. * The number of dimensions is called the rank and the size along each dimension is called the shape. * In NumPy, arrays are called ndarray and elements are accessed using square brackets [], often created from nested Python lists.
4.2.2 Creating a Numpy array
Arrays in Numpy can be created by multiple ways, with various number of Ranks, defining the size of the Array. Arrays can also be created with the use of various data types such as lists, tuples, etc. The type of the resultant array is deduced from the type of the elements in the sequences.
import numpy as np
arr = np.array([1, 2, 3])
print(arr)
arr = np.array([[1, 2, 3],
[4, 5, 6]])
print(arr)
arr = np.array((1, 3, 2))
print(arr)What is happening here?
Array with Rank 1: [1 2 3] Array with Rank 2: [[1 2 3] [4 5 6]]
Array created using passed tuple: [1 3 2]
4.2.3 Accessing the Array Index
In a numpy array, indexing or accessing the array index can be done in multiple ways. To print a range of an array, slicing is done. Slicing of an array is defining a range in a new array which is used to print a range of elements from the original array. Since, sliced array holds a range of elements of the original array, modifying content with the help of sliced array modifies the original array content.
import numpy as np
arr = np.array([[-1, 2, 0, 4],
[4, -0.5, 6, 0],
[2.6, 0, 7, 8],
[3, -7, 4, 2.0]])
arr2 = arr[:2, ::2]
print ("first 2 rows and alternate columns(0 and 2):\n", arr2)
arr3 = arr[[1, 1, 0, 3],
[3, 2, 1, 0]]
print ("\nElements at indices (1, 3), "
"(1, 2), (0, 1), (3, 0):\n", arr3)4.2.4 Basic Array Operations
In numpy, arrays allow a wide range of operations which can be performed on a particular array or a combination of Arrays. These operations include some basic Mathematical operation as well as Unary and Binary operations.
import numpy as np
a = np.array([[1, 2],
[3, 4]])
b = np.array([[4, 3],
[2, 1]])
print ("Adding 1 to every element:", a + 1)
print ("\nSubtracting 2 from each element:", b - 2)
print ("\nSum of all array elements: ", a.sum())
print ("\nArray sum:\n", a + b)4.3 Biopython
So far, we worked with sequences like:
“ATGCGTAA”
👉 But real data looks like this:
“>seq1”
“ATGCGTAGGCTA”
“>seq2”
“TTAGGCGG”
This is a FASTA file
Problem
How do we read this with Python?
❌ Complex
❌ Error-prone
❌ Not scalable
💡 Solution: Biopython
Biopython is a library designed for working with biological data.
👉 It provides tools to: - Read sequence files (FASTA, GenBank, etc.)
- Manipulate sequences
- Perform biological analyses
https://www.mintlify.com/biopython/biopython
—- Let’s do an example! —-
from Bio import SeqIO
for record in SeqIO.parse("example.fasta", "fasta"):
print(record.id)
print(record.seq)What is happening here?
- Biopython reads the file
- Each sequence becomes an object
- We can access:
- record.id
- record.seq
- record.id
—- Let’s do an example! —-
Operations with sequences
from Bio.Seq import Seq
seq = Seq("ATGCGT")
print(seq.reverse_complement())4.4 Exercises
Exercise 1
Consider the following function:
def myFun(x):
print(x * 2)
result = myFun(5)Questions:
- What is printed on the screen?
- What is stored in the variable
result?
- Why? Explain in your own words
# Write your answer hereExercise 2
Consider the function:
def example(a, b=10, *args, **kwargs):
passAnd the following function call:
example(5, 20, 30, 40, x=1, y=2)Questions:
- What is the value of
a?
- What is the value of
b?
- What is stored in
args?
- What is stored in
kwargs?
- Which type of argument is each one?
# Write your answer hereExercise 3 — Array manipulations
Create a NumPy array with the numbers from 1 to 10.
- Multiply all numbers by 3
- Add 5 to all numbers
- Create a boolean array that is True for numbers greater than 20
- Print the result of filtering the original array using this boolean array
# Write your answer hereExercise 4 — 2D Array manipulations
Create the following 2x3 NumPy array:
[[1, 2, 3], [4, 5, 6]]
- Print the shape of the array
- Extract the first row
- Extract the second column
- Multiply the entire array by 2 and print the result
# Write your answer hereExercise 5 — Reading sequences
Using Biopython, read the sequences from a file example.fasta.
- Print the ID of each sequence
- Print the length of each sequence
- Print the first 10 nucleotides of each sequence
# Write your answer hereExercise 6 — Sequence operations
Using Biopython:
- Create a sequence
ATGCGTACusingSeq - Print its complement
- Print its reverse complement
- Print its length
# Write your answer here